using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Web;
using System.Web.UI;
using Sedna.Core.Common.Objects.Navigation;
using Sedna.Core.Controller.Configurations;
using Sedna.Core.Controls;
using Sedna.Core.Controls.Support;
using Sedna.Core.Controls.Support.Javascript;
using Sedna.Core.DataBinding;
using Sedna.Core.Tiles;
using Sedna.Core.Tiles.Contents;
using Sedna.Core.Tiles.Holder;
using log4net;
using Spring.Util;
//using DataBinder=System.Web.UI.DataBinder;
using Page = Spring.Web.UI.Page;
using DataBinder = Sedna.Core.DataBinding.DataBinder;

namespace Sedna.Core.Controller
{
    public class BasePage : Page, IConfigurationAware, IControlDataLoadAware, IControlAfterDataLoadAware, IHttpHandler, IPageWithTabHeader
	{
        private const string JS_ACTION_HIDDEN_NAME = "sedna_action_hidden";
	    
		private ILog log = LogManager.GetLogger(typeof(BasePage));
		private IExecutionContext executionContext = new ExecutionContext(ScopePathParser.Instance);
        protected IDataBinder binder;
		private string configurationId = "configuration.default.BasePage";
		private IPageConfiguration configuration;
        private string masterPageContentPlaceHolderId;

        private string helpPage;
		private PlaceHolderContainer rootPlaceHolderContainer;
		private IContentCollection contents;

		private String workflowId;	    
	    
		#region Properties

        public virtual string TabHeaderLabel
        {
            get
            {
                if (!String.IsNullOrEmpty(Configuration.TabHeaderTextBindPath))
                {
                    String value = ExecutionContext.GetPropertyValue(Configuration.TabHeaderTextBindPath) as String;
                    
                    if (!String.IsNullOrEmpty(value))
                        return value;
                }
                
                String headerKey = Configuration.TabHeaderTextKey;
                
                if (!StringUtils.IsNullOrEmpty(Configuration.TabHeaderTextKeyBindPath))
                {
                    Object header = ExecutionContext.GetPropertyValue(Configuration.TabHeaderTextKeyBindPath);
                    
                    if (header != null)
                        headerKey = String.Format("{0}", header);
                }
                
                return Configuration.GetLocalizedPostfixLabel(headerKey);
            }
        }

        public String WorkflowId
		{
			get { return workflowId;}
			set { workflowId = value;}
		}

		public IExecutionContext ExecutionContext
		{
			get { return executionContext; }
		}

		protected IPageConfiguration Configuration
		{
			get { return configuration; }
			set { configuration = value; }
		}
		
		IConfiguration IConfigurationAware.Configuration
		{
			get { return configuration; }
			set { configuration = (IPageConfiguration) value; }
		}

		public string ConfigurationId
		{
			get { return configurationId; }
			set { configurationId = value; }
		}

		protected string SessionKey
		{
			get
			{
				IPageConfiguration pageConfiguration=Configuration;
				if (pageConfiguration==null||pageConfiguration.SessionKey==null)
				{
					return Request.FilePath;
				}

				return pageConfiguration.SessionKey;
			}
		}

        public string HelpPage
        {
            get { return helpPage; }
            set { helpPage = value; }
        }

        /// <summary>
        /// Id of the master page asp:contentplaceholder on the  to inject this page to
        /// </summary>
        public string MasterPageContentPlaceHolderId
        {
            get { return masterPageContentPlaceHolderId; }
            set { masterPageContentPlaceHolderId = value; }
        }

        #endregion


        #region Javascript support


	    private void DeclareScriptVariable()
        {
            //To make ASP.NET include web resource javascript
            ClientScript.GetPostBackEventReference(
                new PostBackOptions(JavascriptEmitter.Current, null, null, false, false, false, true, true, null));
            
            JavascriptController.Current.DeclareClass(configuration.JavascriptClass);
            if (configuration.ClientVariable != null)
            {
                IDictionary parameters = BuildScriptParameters();
                object[] arr = new object[parameters.Count];
                parameters.Values.CopyTo(arr, 0);
                JavascriptController.Current.DeclareObject(configuration.ClientVariable, configuration.JavascriptClass,  arr);
            }
        }

        protected virtual IDictionary BuildScriptParameters()
        {            
            IDictionary parameters = new ListDictionary();
            parameters.Add("frame", String.IsNullOrEmpty(configuration.FrameClientVariable) ? "null" : configuration.FrameClientVariable);
            parameters.Add("grid", String.IsNullOrEmpty(configuration.GridClientVariable) ? "null" : configuration.GridClientVariable);
            parameters.Add("editPageUrl", JavascriptUtil.EncloseWithQuotes(configuration.EditPageUrl));
            parameters.Add("addPageUrl", JavascriptUtil.EncloseWithQuotes(configuration.AddPageUrl));
            parameters.Add("delMessage", JavascriptUtil.EncloseWithQuotes(configuration.GetLocalizedPostfixLabel(configuration.DelMessageKey)));
            parameters.Add("helpPageUrl", JavascriptUtil.EncloseWithQuotes(ResolveUrl(helpPage)));
            parameters.Add("printPageUrl", JavascriptUtil.EncloseWithQuotes(ResolveUrl(Configuration.PrintPageUrl)));
            parameters.Add("actionName", JavascriptUtil.EncloseWithQuotes(JS_ACTION_HIDDEN_NAME));
            parameters.Add("action", JavascriptUtil.EncloseWithQuotes(Context.Request.Params[JS_ACTION_HIDDEN_NAME]));
            return parameters;
        }

	    
        #endregion

        #region Attributes Support

        public IDictionary Attributes
		{
			get
			{
				if ((Session[AttributesKey] as IDictionary) == null)
				{
					Session[AttributesKey] = new Hashtable();
				}

				return (IDictionary)Session[AttributesKey];
			}
		}

		private void InitializeAttributes()
		{
			if (!IsPostBack)
			{
				Session[AttributesKey] = null;
			}
		}

		private String AttributesKey
		{
			get { return String.Format("Attributes{0}", Request.Url.LocalPath);}
		}

		#endregion

		#region Tiles Support

		/// <summary>
		/// This container defines the main layout of elements on page 
		/// which can be described in a configuration
		/// </summary>
		public virtual PlaceHolderContainer RootPlaceHolderContainer
		{
			get { return rootPlaceHolderContainer;}
			set { rootPlaceHolderContainer = value;}
		}

		public virtual IContentCollection Contents
		{
			get { return contents;}
			set { contents = value;}
		}

		/// <summary>
		/// Assign internal IContent`s to the internal PlaceHolder`s.
		/// Warning! This implementation does not protect from cyclic assignments.
		/// </summary>
		protected virtual void InitializeInternalPlaceHolders()
		{
            log.Debug("Initialazing placeholders for page "+this.TabHeaderLabel);
            PlaceHolderManager.AssignContent(this);
            log.Debug("Finished initialazing placeholders for page " + this.TabHeaderLabel);
        }

/*
		/// <summary>
		/// Assign internal IContent`s to the external PlaceHolder`s
		/// </summary>
		protected override void InitializeMasterPlaceHolders()
		{
			//PENDING: Transitive dependence of the Master Pages

			if (Master is BasePage)
			{
				PlaceHolderManager.AssignContent(this, (BasePage)Master);
			}

			Controls.AddAt(0, Master);
		}
*/

		#endregion

		#region Current IHttpHandler Support

		/// <summary>
		/// Get Current IHttpHandler as BasePage
		/// </summary>
		public static BasePage Current
		{
			get { return HttpContext.Current.Session[CurrentHandlerKey] as BasePage;}
		}

		private static String CurrentHandlerKey
		{
			get { return String.Format("Handler{0}", HttpContext.Current.Request.Url.LocalPath);}
		}

        public override void ProcessRequest(HttpContext context)
        {
            if (context.Session != null)
            {
                context.Session[CurrentHandlerKey] = this;
            }
            base.ProcessRequest(context);
        }
	    
		#endregion

		public override void Dispose()
		{
			/* Clean Current IHttpHandler reference */
			Session[CurrentHandlerKey] = null;

			base.Dispose();
		}

		protected override void RaisePostBackEvent(IPostBackEventHandler sourceControl, string eventArgument)
		{
		    ICommandAware commandAware = sourceControl as ICommandAware;
		    if (commandAware!=null)
		    {
                ExecutionContext["infrastructure.commandName"] = commandAware.CommandName;
                ExecutionContext["infrastructure.commandArgument"] = commandAware.CommandArgument;
		    }
			base.RaisePostBackEvent(sourceControl, eventArgument);
		}

        protected override void OnPreInit(EventArgs e)
        {
            //This should not be in OnInit as controls may put something into Page scope during their OnInit stage
            InitializeAttributes();

            base.OnPreInit(e);
        }
	    
		protected override void OnInit(EventArgs e)
		{
		    
			if (configuration == null)
			{
				configuration = (IPageConfiguration)SpringContextFactory.GetContext().GetObject(configurationId);
			}

		    if (!Configuration.IsVisibleForPrincipal())
                throw new SednaException(SednaExceptionCodes.NotAuthorizedOperation);
            /* Assign IContent`s to the PlaceHolder`s */
			InitializeInternalPlaceHolders();
            binder = new DataBinder(this, configuration, executionContext);
            helpPage = Configuration.GetLocalizedContextHelpPath();
		    
			base.OnInit(e);
		}

		protected override void OnLoad(EventArgs e)
		{			
			ExecutionContext["infrastructure.IsPostBack"]=IsPostBack;
			Context.Items["infrastructure.SessionKey"]=SessionKey;
            Unbind();
            ControlUtil.ExecuteOnLoad(executionContext, Context, Configuration, this.ClientID);

			OnLoadHook(e);

			base.OnLoad(e);
			
		}

        public override void Validate()
        {
            ControlUtil.ExecuteOnValidate(executionContext, Context, Configuration, this.ClientID);
            base.Validate();
        }

        public override void Validate(string validationGroup)
        {
            ControlUtil.ExecuteOnValidate(executionContext, Context, Configuration, this.ClientID);
            base.Validate(validationGroup);
        }

		/// <summary>
		/// override this method if it is necessary to do some work BEFORE the generic Page.OnLoad()
		/// method is called
		/// </summary>
		/// <param name="e"></param>
		protected virtual void OnLoadHook(EventArgs e)
		{}

	    
	    
	    
		protected override void OnPreRender(EventArgs e)
		{
			log.Debug("Start BasePage.OnPreRender");
			DataLoad(this);
			base.OnPreRender(e);
            Bind();
            
		    ControlUtil.ExecuteOnPreRender(executionContext, Context, Configuration, this.ClientID);

		    if (configuration.ClientScriptingEnabled)
            {
                DeclareScriptVariable();
            }
		    if (executionContext.AlertMessage!=null||executionContext.AlertMessageKey!=null)
		    {
		        ClientScript.RegisterStartupScript(typeof(BasePage), "alertMessage", String.Format("window.onload=function() {{alert(\"{0}\")}}", JavascriptUtil.ToStringLiteral(Configuration.GetLocalizedPostfixLabel(executionContext.AlertMessageKey, executionContext.AlertMessage))), true);
		    }
		    log.Debug("Finish BasePage.OnPreRender");
        }

        protected override void OnPreRenderComplete(EventArgs e)
        {
            log.Debug("Start BasePage.OnPreRenderComplete");
            AfterDataLoad(this);
            base.OnPreRenderComplete(e);
        }

        #region IControlDataLoadAware
        
        public virtual void OnDataLoad()
        {
            ControlUtil.ExecuteOnDataLoad(executionContext, Context, Configuration, this.ClientID);
        }

        private void DataLoad(System.Web.UI.Control control)
		{
			if (control == null)
			{
				return;
			}

			IControlDataLoadAware controlDataLoadAware = control as IControlDataLoadAware;
			if (controlDataLoadAware != null)
			{
				if (log.IsDebugEnabled)
				{
					log.Debug("Load Data for control.id = " + control.ID);
				}
				controlDataLoadAware.OnDataLoad();
			}

			if (control.Controls == null || control.Controls.Count == 0)
			{
				return;
			}
	
			for (int i = 0; i < control.Controls.Count; i++)
			{
				DataLoad(control.Controls[i]);
			}
        }

        #endregion

        #region IControlAfterDataLoadAware

        public void OnAfterDataLoad()
        {
            ControlUtil.ExecuteOnAfterDataLoad(executionContext, Context, Configuration, this.ClientID);
        }

        private void AfterDataLoad(System.Web.UI.Control control)
        {
            if (control == null)
            {
                return;
            }

            IControlAfterDataLoadAware controlDataLoadAware = control as IControlAfterDataLoadAware;
            if (controlDataLoadAware != null)
            {
                if (log.IsDebugEnabled)
                {
                    log.Debug("After Load Data for control.id = " + control.ID);
                }
                controlDataLoadAware.OnAfterDataLoad();
            }

            if (control.Controls == null || control.Controls.Count == 0)
            {
                return;
            }

            for (int i = 0; i < control.Controls.Count; i++)
            {
                AfterDataLoad(control.Controls[i]);
            }
        }
        
        #endregion

        protected override void OnError(EventArgs e)
        {
            Exception ex = HttpContext.Current.Server.GetLastError();
            IActionExecutor actionExecutor = (IActionExecutor)SpringContextFactory.GetContext().GetObject("runtime.ActionExecutor");
            actionExecutor.HandleException(ExecutionContext, configuration, ex);
                    
//            IExceptionHandler handler = actionExecutor.LookupExceptionHandler(configuration, ex);
//            handler.HandleException(executionContext, ex);
            base.OnError(e);
        }

        protected override void OnUnload(EventArgs e)
        {
            base.OnUnload(e);
            ControlUtil.ExecuteOnUnload(executionContext, Context, Configuration, this.ClientID);
        }


        protected virtual void Bind()
        {
            if (binder.Bind("HelpPage"))
                helpPage = Configuration.GetLocalizedContextHelpPath(helpPage);
        }

        protected virtual void Unbind()
        {
            binder.Unbind("HelpPage");
        }

	}
}
